{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "###### Content under Creative Commons Attribution license CC-BY 4.0, code under BSD 3-Clause License © 2018  by D. Koehn, notebook style sheet by L.A. Barba, N.C. Clementi"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<link href=\"https://fonts.googleapis.com/css?family=Merriweather:300,300i,400,400i,700,700i,900,900i\" rel='stylesheet' >\n",
       "<link href=\"https://fonts.googleapis.com/css?family=Source+Sans+Pro:300,300i,400,400i,700,700i\" rel='stylesheet' >\n",
       "<link href='http://fonts.googleapis.com/css?family=Source+Code+Pro:300,400' rel='stylesheet' >\n",
       "<style>\n",
       "\n",
       "@font-face {\n",
       "    font-family: \"Computer Modern\";\n",
       "    src: url('http://mirrors.ctan.org/fonts/cm-unicode/fonts/otf/cmunss.otf');\n",
       "}\n",
       "\n",
       "\n",
       "#notebook_panel { /* main background */\n",
       "    background: rgb(245,245,245);\n",
       "}\n",
       "\n",
       "div.cell { /* set cell width */\n",
       "    width: 800px;\n",
       "}\n",
       "\n",
       "div #notebook { /* centre the content */\n",
       "    background: #fff; /* white background for content */\n",
       "    width: 1000px;\n",
       "    margin: auto;\n",
       "    padding-left: 0em;\n",
       "}\n",
       "\n",
       "#notebook li { /* More space between bullet points */\n",
       "margin-top:0.5em;\n",
       "}\n",
       "\n",
       "/* draw border around running cells */\n",
       "div.cell.border-box-sizing.code_cell.running { \n",
       "    border: 1px solid #111;\n",
       "}\n",
       "\n",
       "/* Put a solid color box around each cell and its output, visually linking them*/\n",
       "div.cell.code_cell {\n",
       "    background-color: rgb(256,256,256); \n",
       "    border-radius: 0px; \n",
       "    padding: 0.5em;\n",
       "    margin-left:1em;\n",
       "    margin-top: 1em;\n",
       "}\n",
       "\n",
       "\n",
       "div.text_cell_render{\n",
       "    font-family: 'Source Sans Pro', sans-serif;\n",
       "    line-height: 140%;\n",
       "    font-size: 110%;\n",
       "    width:680px;\n",
       "    margin-left:auto;\n",
       "    margin-right:auto;\n",
       "}\n",
       "\n",
       "/* Formatting for header cells */\n",
       ".text_cell_render h1 {\n",
       "    font-family: 'Merriweather', serif;\n",
       "    font-style:regular;\n",
       "    font-weight: bold;    \n",
       "    font-size: 250%;\n",
       "    line-height: 100%;\n",
       "    color: #004065;\n",
       "    margin-bottom: 1em;\n",
       "    margin-top: 0.5em;\n",
       "    display: block;\n",
       "}\t\n",
       ".text_cell_render h2 {\n",
       "    font-family: 'Merriweather', serif;\n",
       "    font-weight: bold; \n",
       "    font-size: 180%;\n",
       "    line-height: 100%;\n",
       "    color: #0096d6;\n",
       "    margin-bottom: 0.5em;\n",
       "    margin-top: 0.5em;\n",
       "    display: block;\n",
       "}\t\n",
       "\n",
       ".text_cell_render h3 {\n",
       "    font-family: 'Merriweather', serif;\n",
       "\tfont-size: 150%;\n",
       "    margin-top:12px;\n",
       "    margin-bottom: 3px;\n",
       "    font-style: regular;\n",
       "    color: #008367;\n",
       "}\n",
       "\n",
       ".text_cell_render h4 {    /*Use this for captions*/\n",
       "    font-family: 'Merriweather', serif;\n",
       "    font-weight: 300; \n",
       "    font-size: 100%;\n",
       "    line-height: 120%;\n",
       "    text-align: left;\n",
       "    width:500px;\n",
       "    margin-top: 1em;\n",
       "    margin-bottom: 2em;\n",
       "    margin-left: 80pt;\n",
       "    font-style: regular;\n",
       "}\n",
       "\n",
       ".text_cell_render h5 {  /*Use this for small titles*/\n",
       "    font-family: 'Source Sans Pro', sans-serif;\n",
       "    font-weight: regular;\n",
       "    font-size: 130%;\n",
       "    color: #e31937;\n",
       "    font-style: italic;\n",
       "    margin-bottom: .5em;\n",
       "    margin-top: 1em;\n",
       "    display: block;\n",
       "}\n",
       "\n",
       ".text_cell_render h6 { /*use this for copyright note*/\n",
       "    font-family: 'Source Code Pro', sans-serif;\n",
       "    font-weight: 300;\n",
       "    font-size: 9pt;\n",
       "    line-height: 100%;\n",
       "    color: grey;\n",
       "    margin-bottom: 1px;\n",
       "    margin-top: 1px;\n",
       "}\n",
       "\n",
       "    .CodeMirror{\n",
       "            font-family: \"Source Code Pro\";\n",
       "\t\t\tfont-size: 90%;\n",
       "    }\n",
       "/*    .prompt{\n",
       "        display: None;\n",
       "    }*/\n",
       "\t\n",
       "    \n",
       "    .warning{\n",
       "        color: rgb( 240, 20, 20 )\n",
       "        }  \n",
       "</style>\n",
       "<script>\n",
       "    MathJax.Hub.Config({\n",
       "                        TeX: {\n",
       "                           extensions: [\"AMSmath.js\"], \n",
       "                           equationNumbers: { autoNumber: \"AMS\", useLabelIds: true}\n",
       "                           },\n",
       "                tex2jax: {\n",
       "                    inlineMath: [ ['$','$'], [\"\\\\(\",\"\\\\)\"] ],\n",
       "                    displayMath: [ ['$$','$$'], [\"\\\\[\",\"\\\\]\"] ]\n",
       "                },\n",
       "                displayAlign: 'center', // Change this to 'center' to center equations.\n",
       "                \"HTML-CSS\": {\n",
       "                    styles: {'.MathJax_Display': {\"margin\": 4}}\n",
       "                }\n",
       "        });\n",
       "</script>\n"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "execution_count": 1,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# Execute this cell to load the notebook's style sheet, then ignore it\n",
    "from IPython.core.display import HTML\n",
    "css_file = '../style/custom.css'\n",
    "HTML(open(css_file, \"r\").read())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Performance optimization of the 2D acoustic finite difference modelling code\n",
    "\n",
    "During the [last class](http://nbviewer.jupyter.org/github/daniel-koehn/Theory-of-seismic-waves-II/blob/master/05_2D_acoustic_FD_modelling/1_From_1D_to_2D_acoustic_FD_modelling_final.ipynb), it took us only 15 minutes to develop a 2D acoustic FD code based on the 1D code. However, with a runtime of roughly 3 minutes, the performance of this \"vanilla\" Python implementation was quite underwhelming. Therefore, the aim of this lesson is to optimize the performance of this code. \n",
    "\n",
    "Let's start with a slightly modified version of the original code. Basically, I moved the computation of the analytical solution outside the main code, the discretization parameters $nx,\\; nz,\\; nt,\\; dx,\\; dz,\\; dt$ are also fixed in order to minimize the input to the FD modelling function."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "code_folding": [
     0
    ]
   },
   "outputs": [],
   "source": [
    "# Import Libraries \n",
    "# ----------------\n",
    "import numpy as np\n",
    "import matplotlib\n",
    "import matplotlib.pyplot as plt\n",
    "from pylab import rcParams\n",
    "\n",
    "# Ignore Warning Messages\n",
    "# -----------------------\n",
    "import warnings\n",
    "warnings.filterwarnings(\"ignore\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "code_folding": [],
    "scrolled": false
   },
   "outputs": [],
   "source": [
    "# Definition of modelling parameters\n",
    "# ----------------------------------\n",
    "xmax = 500.0 # maximum spatial extension of the 1D model in x-direction (m)\n",
    "zmax = xmax  # maximum spatial extension of the 1D model in z-direction(m)\n",
    "dx   = 1.0   # grid point distance in x-direction\n",
    "dz   = dx    # grid point distance in z-direction\n",
    "\n",
    "tmax = 0.502   # maximum recording time of the seismogram (s)\n",
    "dt   = 0.0010  # time step\n",
    "\n",
    "vp0  = 580.   # P-wave speed in medium (m/s)\n",
    "\n",
    "# acquisition geometry\n",
    "xr = 330.0 # x-receiver position (m)\n",
    "zr = xr    # z-receiver position (m)\n",
    "\n",
    "xsrc = 250.0 # x-source position (m)\n",
    "zsrc = 250.0 # z-source position (m)\n",
    "\n",
    "f0   = 40. # dominant frequency of the source (Hz)\n",
    "t0   = 4. / f0 # source time shift (s)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "nx =  500\n",
      "nz =  500\n",
      "nt =  502\n"
     ]
    }
   ],
   "source": [
    "# define model discretization\n",
    "# ---------------------------\n",
    "\n",
    "nx = (int)(xmax/dx) # number of grid points in x-direction\n",
    "print('nx = ',nx)\n",
    "\n",
    "nz = (int)(zmax/dz) # number of grid points in x-direction\n",
    "print('nz = ',nz)\n",
    "\n",
    "nt = (int)(tmax/dt) # maximum number of time steps            \n",
    "print('nt = ',nt)\n",
    "\n",
    "ir = (int)(xr/dx)      # receiver location in grid in x-direction    \n",
    "jr = (int)(zr/dz)      # receiver location in grid in z-direction\n",
    "\n",
    "isrc = (int)(xsrc/dx)  # source location in grid in x-direction\n",
    "jsrc = (int)(zsrc/dz)  # source location in grid in x-direction\n",
    "\n",
    "# Source time function (Gaussian)\n",
    "# -------------------------------\n",
    "src  = np.zeros(nt + 1)\n",
    "time = np.linspace(0 * dt, nt * dt, nt)\n",
    "\n",
    "# 1st derivative of a Gaussian\n",
    "src  = -2. * (time - t0) * (f0 ** 2) * (np.exp(- (f0 ** 2) * (time - t0) ** 2))\n",
    "\n",
    "# Analytical solution\n",
    "# -------------------\n",
    "G    = time * 0.\n",
    "\n",
    "# Initialize coordinates\n",
    "# ----------------------\n",
    "x    = np.arange(nx)\n",
    "x    = x * dx       # coordinates in x-direction (m)\n",
    "\n",
    "z    = np.arange(nz)\n",
    "z    = z * dz       # coordinates in z-direction (m)\n",
    "\n",
    "# calculate source-receiver distance\n",
    "r = np.sqrt((x[ir] - x[isrc])**2 + (z[jr] - z[jsrc])**2)\n",
    "\n",
    "for it in range(nt): # Calculate Green's function (Heaviside function)\n",
    "    if (time[it] - r / vp0) >= 0:\n",
    "        G[it] = 1. / (2 * np.pi * vp0**2) * (1. / np.sqrt(time[it]**2 - (r/vp0)**2))\n",
    "Gc   = np.convolve(G, src * dt)\n",
    "Gc   = Gc[0:nt]\n",
    "lim  = Gc.max() # get limit value from the maximum amplitude\n",
    "\n",
    "# Initialize model (assume homogeneous model)\n",
    "# -------------------------------------------\n",
    "vp    = np.zeros((nx,nz))\n",
    "vp2    = np.zeros((nx,nz))\n",
    "\n",
    "vp  = vp + vp0       # initialize wave velocity in model\n",
    "vp2 = vp**2"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "code_folding": [
     42
    ]
   },
   "outputs": [],
   "source": [
    "# 2D Wave Propagation (Finite Difference Solution) \n",
    "# ------------------------------------------------\n",
    "def FD_2D_acoustic_vanilla():        \n",
    "    \n",
    "    # Initialize empty pressure arrays\n",
    "    # --------------------------------\n",
    "    p    = np.zeros((nx,nz)) # p at time n (now)\n",
    "    pold = np.zeros((nx,nz)) # p at time n-1 (past)\n",
    "    pnew = np.zeros((nx,nz)) # p at time n+1 (present)\n",
    "    d2px = np.zeros((nx,nz)) # 2nd spatial x-derivative of p\n",
    "    d2pz = np.zeros((nx,nz)) # 2nd spatial z-derivative of p\n",
    "\n",
    "    # Initialize empty seismogram\n",
    "    # ---------------------------\n",
    "    seis = np.zeros(nt) \n",
    "    \n",
    "    # Calculate Partial Derivatives\n",
    "    # -----------------------------\n",
    "    for it in range(nt):\n",
    "    \n",
    "        # FD approximation of spatial derivative by 3 point operator\n",
    "        for i in range(1, nx - 1):\n",
    "            for j in range(1, nz - 1):\n",
    "                \n",
    "                d2px[i,j] = (p[i + 1,j] - 2 * p[i,j] + p[i - 1,j]) / dx ** 2                \n",
    "                d2pz[i,j] = (p[i,j + 1] - 2 * p[i,j] + p[i,j - 1]) / dz ** 2\n",
    "\n",
    "        # Time Extrapolation\n",
    "        # ------------------\n",
    "        pnew = 2 * p - pold + vp ** 2 * dt ** 2 * (d2px + d2pz)\n",
    "\n",
    "        # Add Source Term at isrc\n",
    "        # -----------------------\n",
    "        # Absolute pressure w.r.t analytical solution\n",
    "        pnew[isrc,jsrc] = pnew[isrc,jsrc] + src[it] / (dx * dz) * dt ** 2\n",
    "                \n",
    "        # Remap Time Levels\n",
    "        # -----------------\n",
    "        pold, p = p, pnew\n",
    "    \n",
    "        # Output of Seismogram\n",
    "        # -----------------\n",
    "        seis[it] = p[ir,jr]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "You know what happened the last time, we executed the cell below. We had to wait 4 minutes until the modelling run finished. So for safety reasons I commented the code execution and defined the runtime. You should adapt the value of the timing measurement `t_vanilla_python` by the value of your computer."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [],
   "source": [
    "#%time FD_2D_acoustic_vanilla()\n",
    "t_vanilla_python = 239.0"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Just-In-Time (JIT) code compilation with Numba \n",
    "\n",
    "The poor performance of the vanilla Python code is due to the nested FOR loops to compute the 2nd spatial FD derivatives. We can optimize the performance using the `Numba ` library  for Python ([http://numba.pydata.org/](http://numba.pydata.org/)) which turns Python functions into C-style compiled functions using [LLVM](https://en.wikipedia.org/wiki/LLVM). A nice introduction to Numba was presented at the SciPy conference 2016 by Gil Forsyth & Lorena Barba with the title \n",
    "\n",
    "**Numba: Tell those C++ bullies to get lost**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/jpeg": "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\n",
      "text/html": [
       "\n",
       "        <iframe\n",
       "            width=\"400\"\n",
       "            height=\"300\"\n",
       "            src=\"https://www.youtube.com/embed/SzBi3xdEF2Y\"\n",
       "            frameborder=\"0\"\n",
       "            allowfullscreen\n",
       "        ></iframe>\n",
       "        "
      ],
      "text/plain": [
       "<IPython.lib.display.YouTubeVideo at 0x7fb8e7361e50>"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from IPython.display import YouTubeVideo\n",
    "YouTubeVideo('SzBi3xdEF2Y')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The associated Jupyter notebooks can be cloned from [here](https://github.com/barbagroup/numba_tutorial_scipy2016).\n",
    "\n",
    "First, we have to install Numba, which is quite easy using Anaconda:\n",
    "\n",
    "`conda install numba` \n",
    "\n",
    "From the Numba library we import **jit**: "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [],
   "source": [
    "# import JIT from Numba\n",
    "from numba import jit"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The only thing, we modify in our original Python code is to add the function decorator \n",
    "\n",
    "`@jit(nopython=True)`\n",
    "\n",
    "which tags the function `FD_2D_acoustic_JIT` to be compiled:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [],
   "source": [
    "# FD_2D_acoustic code with JIT optimization\n",
    "# -----------------------------------------\n",
    "@jit(nopython=True) # use Just-In-Time (JIT) Compilation for C-performance\n",
    "def FD_2D_acoustic_JIT():        \n",
    "    \n",
    "    # Initialize empty pressure arrays\n",
    "    # --------------------------------\n",
    "    p    = np.zeros((nx,nz)) # p at time n (now)\n",
    "    pold = np.zeros((nx,nz)) # p at time n-1 (past)\n",
    "    pnew = np.zeros((nx,nz)) # p at time n+1 (present)\n",
    "    d2px = np.zeros((nx,nz)) # 2nd spatial x-derivative of p\n",
    "    d2pz = np.zeros((nx,nz)) # 2nd spatial z-derivative of p\n",
    "\n",
    "    # Initialize empty seismogram\n",
    "    # ---------------------------\n",
    "    seis = np.zeros(nt) \n",
    "    \n",
    "    # Calculate Partial Derivatives\n",
    "    # -----------------------------\n",
    "    for it in range(nt):\n",
    "    \n",
    "        # FD approximation of spatial derivative by 3 point operator\n",
    "        for i in range(1, nx - 1):\n",
    "            for j in range(1, nz - 1):\n",
    "                \n",
    "                d2px[i,j] = (p[i + 1,j] - 2 * p[i,j] + p[i - 1,j]) / dx**2                \n",
    "                d2pz[i,j] = (p[i,j + 1] - 2 * p[i,j] + p[i,j - 1]) / dz**2\n",
    "\n",
    "        # Time Extrapolation\n",
    "        # ------------------\n",
    "        pnew = 2 * p - pold + vp2 * dt**2 * (d2px + d2pz)\n",
    "\n",
    "        # Add Source Term at isrc\n",
    "        # -----------------------\n",
    "        # Absolute pressure w.r.t analytical solution\n",
    "        pnew[isrc,jsrc] = pnew[isrc,jsrc] + src[it] / (dx * dz) * dt ** 2\n",
    "                \n",
    "        # Remap Time Levels\n",
    "        # -----------------\n",
    "        pold, p = p, pnew\n",
    "    \n",
    "        # Output of Seismogram\n",
    "        # -----------------\n",
    "        seis[it] = p[ir,jr]   \n",
    "        \n",
    "    return seis"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Let's run the code:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "CPU times: user 372 ms, sys: 0 ns, total: 372 ms\n",
      "Wall time: 373 ms\n"
     ]
    }
   ],
   "source": [
    "%time seis_FD_JIT = FD_2D_acoustic_JIT()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Wow, you don't have to wait 4 minutes, but only 796 ms. Run the cell above again ...\n",
    "\n",
    "... and you see that the runtime is suddenly further decreased to 372 ms. This performance improvement can be explained by the code compilation during the first run of the code. So by simply using the `@jit` function decorator we get a performance increase of almost **642x** compared to the non-optimized Python code.\n",
    "\n",
    "Generally, it is a good idea to estimate the performance of a code based on multiple runtime estimations instead of just one. To achieve this replace the magic function `%time` by `%timeit`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "349 ms ± 12.4 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)\n"
     ]
    }
   ],
   "source": [
    "%timeit seis_FD_JIT = FD_2D_acoustic_JIT()\n",
    "\n",
    "# run code again to compute seismogram for JIT compiled Python code\n",
    "seis_FD_JIT = FD_2D_acoustic_JIT()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Replace the runtime of the JIT compiled Python code in the cell below by your own runtime measurement"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [],
   "source": [
    "t_JIT_python = 0.349  # runtime of JIT compiled Python code (s)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Another approach to get rid of the nested FOR-loops is to use Numpy array operations:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [],
   "source": [
    "# FD_2D_acoustic code with NumPy arrays\n",
    "# -------------------------------------\n",
    "def FD_2D_acoustic_numpy():        \n",
    "    \n",
    "    # Initialize empty pressure arrays\n",
    "    # --------------------------------\n",
    "    p    = np.zeros((nx,nz)) # p at time n (now)\n",
    "    pold = np.zeros((nx,nz)) # p at time n-1 (past)\n",
    "    pnew = np.zeros((nx,nz)) # p at time n+1 (present)\n",
    "    d2px = np.zeros((nx,nz)) # 2nd spatial x-derivative of p\n",
    "    d2pz = np.zeros((nx,nz)) # 2nd spatial z-derivative of p\n",
    "\n",
    "    # Initialize empty seismogram\n",
    "    # ---------------------------\n",
    "    seis = np.zeros(nt) \n",
    "    \n",
    "    # Calculate Partial Derivatives\n",
    "    # -----------------------------\n",
    "    for it in range(nt):    \n",
    "\n",
    "        # Old FD approximation of spatial derivative by 3-point operator\n",
    "        # using nested FOR-loops is replaced by ...\n",
    "        #for i in range(1, nx - 1):\n",
    "        #    for j in range(1, nz - 1):\n",
    "        #        \n",
    "        #        d2px[i,j] = (p[i + 1,j] - 2 * p[i,j] + p[i - 1,j]) / dx**2                \n",
    "        #        d2pz[i,j] = (p[i,j + 1] - 2 * p[i,j] + p[i,j - 1]) / dz**2\n",
    "        \n",
    "        # ... Numpy array operations:\n",
    "        d2px[1:-2,1:-2] = (p[2:-1,1:-2] - 2 * p[1:-2,1:-2] + p[0:-3,1:-2]) / dx**2\n",
    "        d2pz[1:-2,1:-2] = (p[1:-2,2:-1] - 2 * p[1:-2,1:-2] + p[1:-2,0:-3]) / dz**2\n",
    "        \n",
    "        # Time Extrapolation\n",
    "        # ------------------\n",
    "        pnew = 2 * p - pold + vp ** 2 * dt ** 2 * (d2px + d2pz)\n",
    "\n",
    "        # Add Source Term at isrc\n",
    "        # -----------------------\n",
    "        # Absolute pressure w.r.t analytical solution\n",
    "        pnew[isrc,jsrc] = pnew[isrc,jsrc] + src[it] / (dx * dz) * dt ** 2\n",
    "                \n",
    "        # Remap Time Levels\n",
    "        # -----------------\n",
    "        pold, p = p, pnew\n",
    "    \n",
    "        # Output of Seismogram\n",
    "        # -----------------\n",
    "        seis[it] = p[ir,jr]   \n",
    "        \n",
    "    return seis"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "2 s ± 2.23 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)\n"
     ]
    }
   ],
   "source": [
    "%timeit seis_FD_numpy = FD_2D_acoustic_numpy()\n",
    "\n",
    "# run code again to compute seismogram for Python code with NumPy array operations\n",
    "seis_FD_numpy = FD_2D_acoustic_numpy()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [],
   "source": [
    "t_numpy_python = 2.0  # runtime of JIT compiled Python code (s)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The runtime 2 s of the `NumPy` version is not as fast as the 0.349 s of the JIT version, but a **119x** improvement is still better than the non-optimized version. Can JIT also improve the performance of `FD_2D_acoustic_numpy`?"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [],
   "source": [
    "# FD_2D_acoustic code with NumPy arrays + JIT\n",
    "# -------------------------------------------\n",
    "@jit(nopython=True) # use Just-In-Time (JIT) Compilation for C-performance\n",
    "def FD_2D_acoustic_numpy_JIT():        \n",
    "    \n",
    "    # Initialize empty pressure arrays\n",
    "    # --------------------------------\n",
    "    p    = np.zeros((nx,nz)) # p at time n (now)\n",
    "    pold = np.zeros((nx,nz)) # p at time n-1 (past)\n",
    "    pnew = np.zeros((nx,nz)) # p at time n+1 (present)\n",
    "    d2px = np.zeros((nx,nz)) # 2nd spatial x-derivative of p\n",
    "    d2pz = np.zeros((nx,nz)) # 2nd spatial z-derivative of p\n",
    "\n",
    "    # Initialize empty seismogram\n",
    "    # ---------------------------\n",
    "    seis = np.zeros(nt) \n",
    "    \n",
    "    # Calculate Partial Derivatives\n",
    "    # -----------------------------\n",
    "    for it in range(nt):    \n",
    "\n",
    "        # Old FD approximation of spatial derivative by 3-point operator\n",
    "        # using Numpy array operations\n",
    "        d2px[1:-2,1:-2] = (p[2:-1,1:-2] - 2 * p[1:-2,1:-2] + p[0:-3,1:-2]) / dx**2\n",
    "        d2pz[1:-2,1:-2] = (p[1:-2,2:-1] - 2 * p[1:-2,1:-2] + p[1:-2,0:-3]) / dz**2\n",
    "        \n",
    "        # Time Extrapolation\n",
    "        # ------------------\n",
    "        pnew = 2 * p - pold + vp ** 2 * dt ** 2 * (d2px + d2pz)\n",
    "\n",
    "        # Add Source Term at isrc\n",
    "        # -----------------------\n",
    "        # Absolute pressure w.r.t analytical solution\n",
    "        pnew[isrc,jsrc] = pnew[isrc,jsrc] + src[it] / (dx * dz) * dt ** 2\n",
    "                \n",
    "        # Remap Time Levels\n",
    "        # -----------------\n",
    "        pold, p = p, pnew\n",
    "    \n",
    "        # Output of Seismogram\n",
    "        # -----------------\n",
    "        seis[it] = p[ir,jr]   \n",
    "        \n",
    "    return seis"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "474 ms ± 4.67 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)\n"
     ]
    }
   ],
   "source": [
    "%timeit seis_FD_numpy_JIT = FD_2D_acoustic_numpy_JIT()\n",
    "\n",
    "# run code again to compute seismogram for JIT compiled Python code \n",
    "# with NumPy array operations\n",
    "\n",
    "seis_FD_numpy_JIT = FD_2D_acoustic_numpy_JIT()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [],
   "source": [
    "t_numpy_python_JIT = 0.474  # runtime of JIT compiled Python code (s)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "So JIT could also improve the performance of the code using `NumPy` array operations, but the performance of the compiled code with the nested FOR loops has a slight edge in terms of performance. "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Comparison with a C++ implementation\n",
    "\n",
    "How does the performance of the JIT-codes compare to a C++ bully code? I invested 1 hour to write [this C++ code](https://github.com/daniel-koehn/Theory-of-seismic-waves-II/tree/master/05_2D_acoustic_FD_modelling/cxx/2dac.cpp), which is similar to the 2D acoustic FD Python code. \n",
    "\n",
    "In order to use similar matrix data structures in C++ as in Python, I use the `Eigen` library:\n",
    "\n",
    "www.eigen.tuxfamily.org/\n",
    "\n",
    "which also allows auto-vectorization of matrix-matrix products. To compile the source code, you need a C++ compiler, e.g. `g++` and the `Eigen` library which can either be compiled from source or installed using the package manager of your Linux distribution. \n",
    "\n",
    "I also recommend to use the moderate optimization option `-O2` and Advanced Vector Extensions ([AVX](https://en.wikipedia.org/wiki/Advanced_Vector_Extensions)) `-mavx` during code compilation for a significant performance increase of the code. Let's compile and run the code:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Wall time: 452.998 ms\r\n"
     ]
    }
   ],
   "source": [
    "# Compile and run C++-version\n",
    "!g++ -I /usr/include/eigen3 cxx/2dac.cpp -o 2dac -O2 -mavx\n",
    "\n",
    "# Run code in Linux\n",
    "!./2dac\n",
    "\n",
    "# Run code in Windows\n",
    "#!2dac\n",
    "\n",
    "# load seismogram\n",
    "time_Cpp, seis_FD_Cpp = np.loadtxt('seis.dat', delimiter='\\t', skiprows=0, unpack=True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {},
   "outputs": [],
   "source": [
    "t_cxx = 0.453  # runtime of C++ code (s)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The C++ code performance is comparable with the JIT version of the Python code using `NumPy` operations, which is quite impressive considering the simple Python code optimization using JIT.\n",
    "\n",
    "To check if the optimized codes are not only fast but still produce reasonable modelling results, it is a good idea to check if the seismograms of the optimized codes still coincide with the analytical solution."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 864x360 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "# Compare FD Seismogram with analytical solution\n",
    "# ----------------------------------------------\n",
    "# Define figure size\n",
    "rcParams['figure.figsize'] = 12, 5\n",
    "plt.plot(time, seis_FD_JIT, 'b-',lw=3,label=\"FD solution (Python + JIT)\") # plot FD seismogram\n",
    "plt.plot(time, seis_FD_numpy, 'g-',lw=3,label=\"FD solution (Python + NumPy)\") # plot FD seismogram\n",
    "plt.plot(time, seis_FD_numpy_JIT, 'k-',lw=3,label=\"FD solution (Python + NumPy + JIT)\") # plot FD seismogram\n",
    "plt.plot(time_Cpp, seis_FD_Cpp, 'y-',lw=3,label=\"FD solution (C++)\") # plot FD seismogram\n",
    "Analy_seis = plt.plot(time,Gc,'r--',lw=3,label=\"Analytical solution\") # plot analytical solution\n",
    "plt.xlim(time[0], time[-1])\n",
    "plt.title('Seismogram')\n",
    "plt.xlabel('Time (s)')\n",
    "plt.ylabel('Amplitude')\n",
    "plt.legend()\n",
    "plt.grid()\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Finally, we produce some nice bar charts to compare the performance of the different codes developed in this `Jupyter` notebook:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {
    "scrolled": false
   },
   "outputs": [
    {
     "data": {
      "image/png": "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zc2VmemBBx7Q4MGDY873wQcf1JAhQ8Kfq1SpooSEBGVmZobTTjrpJL3//vtKS0srNr85c+aoU6dOysnx/hZOPfVUffbZZwWu+9133+mcc84J38BXr15dubm52rHDq2/HHnuspk2bptTU1JiPC9FZsWKFmjVrttf1LC0tTZmZmeHfYa1atfTOO+/otNNOK9E+4lV3UXHsyzrwxBNP6MYbbwx/vvvuuwu8Cb7hhhv05ptvFprPnj17tHnzZknSqFGjNGDAgCL3m5GRoTZt2mjFihXhtIp8n1aRlMf6JSkcZNetW1eJiYkFrvPcc8+pW4WEPhIAACAASURBVLdu+dJbtWqlRYsWhT/XrFlTGRkZys7OliQlJCTooYce0i233FLSQ9nvmdkc51zHvOm0YJUR5wdRbTp1Vu+hI3XfO9/qgXfn6MH35qvvfc+qdsPG2pm+TS8Mv17bN2/It33N+geoy5X99fd/vah73/5G/3r/Bz3w7hw9MGGOLh10r1KqVNW65b/q9X/dlm/bLevXaNy9A7VrR4aatmqvW8ZM0gMTZmvEpHnqPWyUqlRP04L/faopLzxeomP78r3X9PUHb8kSEtS97216cOI8jZg4TwMef121GhyoTWtW6KX7BpUob5Tczp07df7552vTpk3q0KGDfvzxR23btk1btmzRzTffLOechgwZoo8//jjmvNu2basRI0boq6++0tatW7Vjxw5lZGRo/fr1euihh5SUlKSZM2fu9Q+lMLm5ubr22mtlZjr66KOLXDcjI0Pdu3fXmjVr1LJlS82cOVPp6enKyMjQtGnT1KRJE3377bf629/+FvMxIXqhIOq8887Tf//7X23evFnbtm3Tjh07NGXKFB100EHasmWLevToobVr18acfzzrLiqGfVkHVq5cqWHDhqlZs2Zq0KDoLwJHjhyptWvXFvoaOnSoJKlSpUq6/PLLi933sGHDtGLFCnXq1KnUx4Holdf6FWnWrFmF1rOCgitJuuyyyzR27FgtXrxYu3fv1pYtW7R7927NmzdP5513nnJzc3Xrrbfq888/L/VxYW8EWGWkSmoN3fTvd/W3e8eo/SldVTW1hiSvJar1saeq733PKik5Rbt2ZOh/7+f/duygtkepa68BannkcaqWVjOcXrladR1/bk9dcN0dkqRf5n+tLev37poz450XtCszXSlVq+mae55W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b9Z773mTOBUVNGVmZur6669XUlKSnn766cD+b3L9ik15r1/jxo3T2WefrZo1/5gxulWrVho7dmx48o3nnnuuyMk3Lr74Yq1du1br1q3Tjh079MUXX6h169a68sor1aVLF23bti2mMp177rmSvNb/wYMH6+uvvy52huD9DQFWOZK5faueGXKNNq9dqXoHNlff+56NeUxRaq26Ouvyv+uqIY8qO2u33nh4iLZuXLfXOrUbHKg+Q0cppWo1rVu2RM/c3ke3dztCwy7ppHeevEcpVarp9J7ec4OSklPC06xHI9SKVlSrV9auP5YlR7S6Feeym+5Xg6YHK2PrJn3w4kg9+vceuvOijvrP0H6aPW2icvxxY8ivevXq4fc7dxY+02JoVqnI9UvKzNS0aVM98sgjeuyxx7R582b99a9/3evbwtzcXPXr1085OTkaNWpUkd8eFiQ1NVWTJk1Sw4YNtWrVKl100UWqXr260tLSdPnll2vXrl17zUYY+Q+qOM8995xat26t9evXa9iwYerQoYNq1qyp8847T6+88kp4bBcKtnnzZnXp0kVLly5Vy5Yt9f7775dozEc86+6pp56qf/7zn0pKStJ7772niy++WHXr1lXr1q11yy236Jdffom5vAhePOvA6tWrNXToUFWvXl2PPfZYyQsZ4Y033lBWVpaSkpJ0xRVXFLpeqOV+4MCBOvzwwwtdryS4fkWvotWvSHfffbeqVKki51zU47FSUlJ00kknafr06erUqZOmT5+uu+66K6b9PvzwwzrhhBOUnp6uhx56SMcff7zS0tJ0+umn6+mnny7yPO4vCLDKiZ2Z6Xr2jmu09vfFqlW/ka576IV8k1PEou3xp6tWgwOVtXun5n+W/4/usI4n6fb/TNFpl16jJoe2U816B6hRi1Y69eKrdeuYSaqU4t0I1TuwWUz7DY29Kmrs1vZNfwR8abXrRZ13nQOa6JYxk3T13U/puHMvU4OmB2v3zh1a+O0Mvfav2zRyQE/t3plZfEb7och+5UVNxxpadsABBwS6/379+iklJUVr1qzRhx9+GE5/8cUXNWvWLHXp0kWnnXaaMjIy9nqFbgJycnLCaXm/he3QoYMWLFige+65RyeccIKaNm2qtm3b6tprr9X8+fPVrJlXh2vUqFHkDIZ5tWjRQt9//70mTJigfv36qXXr1srIyNCUKVN01VVX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\n",
      "text/plain": [
       "<Figure size 864x576 with 2 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "# define codes\n",
    "codes = ('Python', 'Python + JIT', 'Python + NumPy', 'Python + NumPy + JIT', 'C++')\n",
    "y_pos = np.arange(len(codes))\n",
    "\n",
    "# runtime\n",
    "performance = [t_vanilla_python,t_JIT_python,t_numpy_python,t_numpy_python_JIT,t_cxx]\n",
    "\n",
    "# speed-up with respect to the non-optimized code\n",
    "speedup = [t_vanilla_python/t_vanilla_python,\n",
    "           t_vanilla_python/t_JIT_python,\n",
    "           t_vanilla_python/t_numpy_python,\n",
    "           t_vanilla_python/t_numpy_python_JIT,\n",
    "           t_vanilla_python/t_cxx]\n",
    "\n",
    "# Define figure size\n",
    "rcParams['figure.figsize'] = 12, 8\n",
    "\n",
    "# Plot runtimes of 2D acoustic FD codes\n",
    "ax1 = plt.subplot(211)\n",
    "\n",
    "plt.bar(y_pos, performance, align='center', alpha=0.5)\n",
    "plt.xticks(y_pos, codes)\n",
    "plt.ylabel('Runtime (s)')\n",
    "plt.title('Performance comparison of 2D acoustic FD modelling codes')\n",
    "\n",
    "sname = str(np.round(performance[0],decimals=3)) + ' s'\n",
    "plt.text(y_pos[0]-0.34, performance[0]/10, sname, fontsize=24)\n",
    "\n",
    "sname = str(np.round(performance[1],decimals=3)) + ' s'\n",
    "plt.text(y_pos[1]-0.31, performance[0]/10, sname, fontsize=24)\n",
    "\n",
    "sname = str(np.round(performance[2],decimals=3)) + ' s'\n",
    "plt.text(y_pos[2]-0.31, performance[0]/10, sname, fontsize=24)\n",
    "\n",
    "sname = str(np.round(performance[3],decimals=3)) + ' s'\n",
    "plt.text(y_pos[3]-0.31, performance[0]/10, sname, fontsize=24)\n",
    "\n",
    "sname = str(np.round(performance[4],decimals=3)) + ' s'\n",
    "plt.text(y_pos[4]-0.31, performance[0]/10, sname, fontsize=24)\n",
    "    \n",
    "# make tick labels invisible\n",
    "plt.setp(ax1.get_xticklabels(), visible=False)   \n",
    "\n",
    "# Plot speedup of 2D acoustic FD codes\n",
    "ax2 = plt.subplot(212, sharex=ax1)    \n",
    "\n",
    "plt.bar(y_pos, speedup, align='center', alpha=0.5,color='r')\n",
    "plt.xticks(y_pos, codes)\n",
    "plt.ylabel('Speedup ()')\n",
    "\n",
    "sname = str((int)(np.floor(speedup[1]))) + 'x'\n",
    "plt.text(y_pos[1]-0.31, speedup[1]/2, sname, fontsize=40)\n",
    "\n",
    "sname = str((int)(np.floor(speedup[2]))) + 'x'\n",
    "plt.text(y_pos[2]-0.31, speedup[2]/20, sname, fontsize=40)\n",
    "\n",
    "sname = str((int)(np.floor(speedup[3]))) + 'x'\n",
    "plt.text(y_pos[3]-0.31, speedup[3]/2, sname, fontsize=40)\n",
    "\n",
    "sname = str((int)(np.floor(speedup[4]))) + 'x'\n",
    "plt.text(y_pos[4]-0.31, speedup[4]/2, sname, fontsize=40)\n",
    "\n",
    "plt.tight_layout()\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Is this the best result we can achieve or are further code improvements possible? \n",
    "\n",
    "Using domain decomposition with the **Message-Passing Interface MPI** to distribute the workload over multiple CPU cores, combined with a partioning of the tasks in each domain using **Multithreading** can significantly improve the code performance. One key is the manual optimization of CPU and GPU kernels, especially regarding memory access times or communication between MPI processes. As an example I plotted the runtime and speedup for the same homogeneous acoustic problem from this Jupyter notebook using the 2D acoustic modelling code [DENISE Black-Edition](https://github.com/daniel-koehn/DENISE-Black-Edition) which only relies on MPI:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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7rvvMnbsWJ544gnAqxLefPPNnHnmmXTo0IGVK1dyySWX0LZtW+6+++7gflJTU0lMTCQhIYERI0awZ8+eCju+qsDMWprZMjNbbWZfmdmowPyxZrbezD4PPJLDHUs43lIbNmygSZMm1KlTB4AmTZpw5JFHAt775o477qBr16507dqV77//HoDffvuNSy+9lFNOOYVTTjmF999/H/CGBx4yZAinnHIKnTp1YsGCBQDs3LmTAQMG0LFjR1JSUti5c2dw/w0aNAg+nzFjBldffTXgVYFHjhxJjx49aNeuHfPnzy/xWI4++mj++c9/8swzz5S4btOmTTn33HMLVayLysrKIi8vj8MOOwyAOnXq0L59+xK3LRJtIjuBroR/5iJRpbgvpKGPcL02YM+ePSxdupQ+ffqUav0mTZrw6aefct111/HEE0/Qpk0bRo4cyc0338znn39Ojx499nlN7dq1eeeddxg5ciR9+/ZlwoQJZGRkMGnSJDIzM1m9ejX//ve/SUtL4/PPPycmJoZp06aVKp5qJA+41TnXATgN+IuZHR9Y9pRzLiHweLO8O/LjLZWUlMTPP/9Mu3btuP7663n77bcLLW/YsCErVqzghhtu4KabbgJg1KhR3HzzzaxcuZKZM2cydOhQwGsKcs4557By5UqWLVvG3Xffzfbt23n++eepV68eX375JWPGjOGTTz4p1e9j7dq1vP322yxYsICRI0eW6oa8zp078/XXXwen//3vfxdqwhGavI8ePZonn3xyv1/6Dj30UPr06UPr1q0ZOHAg06ZNIz8/P7i84Mtnt27dOPvss0t1TCJ+mz59Or/99luFblNNOESkytu5cycJCQmsXbuWLl260LNnz1K97pJLLgGgS5cuzJo1q1SvKUjOTzzxRP70pz9xxBFHAF6l7+eff+a9997jk08+ITExkRo1arBz506aNWt2EEdVdTnnNgAbAs+zzGw10NzfqCpOgwYN+OSTT3j33XdZtmwZKSkpPProo8FK8MCBA4M/b775ZgCWLFnCqlWrgtvYtm0bWVlZLF68mDfeeCN4FWPXrl3873//45133uHGG28EoGPHjnTs2LFUsfXv358aNWrQtm1bjj76aL7++msSEhIO+BrnXKHp4ppwFDjqqKPo2rUrr7766n63969//Yv//ve/LFmyhCeeeIK0tLTglR014ZDqZsaMGQwY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4fT3v/+d5557Ljg9cuRIHn744UqNITo+xaE9cehGQhERKcbYsWN54oknAEhMTOSOO+6ga9eutGvXjnfffReAPXv28Le//Y1TTjmFjh078sILLwDe6IbnnnsuPXr04MQTT2Tu3LmA1y1ehw4duP766+ncuTM///xzoX2OHj2a448/no4dOwYrw1dffTUjR46kR48etGvXLniJen/7Bnj88ceD8++9997g/Iceeoj27dtz3nnn8c033wTnJyYm8vHHHwNe918FowlOmjSJvn37csEFF9C+fXvuu+++Cvv9ilSEJ598koceeig4PWDAAMaPH49ZcT1vho8q0CIi4ptw/tMr742veXl5rFixgjfffJP77ruPJUuW8NJLL9GoUSNWrlzJrl276NatG0lJSbRs2ZLZs2djZuzatYvTTjuNPn36APDNN9/wyiuvFKqYAWzZsoXZs2fz9ddfY2Zs3bo1uGzt2rW8/fbb/PDDD5x99tl8//33TJkypdh9f/fdd3z33XesWLEC5xx9+vThnXfeoX79+rz++ut89tln5OXl0blzZ7p06VLica9YsYKMjAzq1avHKaecQu/evTn55JPL9bsUqQgvvfRSoSZIycnJTJkyhZiYmEqPJToSaFWgRUSkjC655BIAunTpEhxgZfHixXz55ZfMmDEDgD/++IPvvvuOFi1acNddd5Genk7NmjVZv349mwL33rRu3ZrTTjttn+03bNiQ2NhYhg4dSu/evbnwwguDy/r370+NGjVo27YtRx99NF9//fV+97148WIWL14cbJOfnZ3Nd999R1ZWFhdffDH16tUDCCb0JenZsyeHBf5vXnLJJbz33ntKoMV3M2bMYPjw4cHpHj16MH36dGrVquVLPNGRQKsCLSIiZVSnTh0AYmJiyMvLA7yq9rPPPsv5559faN1Jkybx22+/8c4773DooYfSpk0bcgLdptavX7/Y7desWZMVK1awdOlSXn/9dcaPH89bb70F7FuZN7P97nvRokXceeedjBgxotD8p59+er8V/po1a5Kfnw8QjDN0XweaFqlsixcvZtCgQcH3bKdOnZg3b17wy6Ef1AZaRER8U3BjXTge4XD++efz/PPPk5ubC8C3337L9u3b+eOPP2jWrBm1atVi2bJl/PTTTyVuKzs7mz/++IPk5GSefvppPv/88+Cy6dOnk5+fzw8//MCa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L1RERERKlJ+fz9VXX01WyBoKY8eOpX///uU6f/duuOYaGDUqGDv1VG9lwQsvDHOyIofhUFegXwJOAZYBvwcygX5Ab+dc7wjnVnk0awZNmniPtay3iIhIqfbv38+gQYOYPHlyUez+++9n6NCh5Tp/82bo2BFefTUYy8iA+fO9P8cilcGhCuimzrmBzrl/A1cBrYFLnHOJNQWSlvUWERE5JOccw4cP5z//+U9R7LbbbmPEiBHlOn/pUjj7bO9Kc6GbboKZM6F27XBnK3L4DlVA7yt84JwrANY653aU98XNrJuZrTKz1WZ2ZxnHXW5mzsxal/e1o04FtIiISJkefPBBHn/88aL966+/ntGjR2Nmhzx3xgxvmrpvv/X2k5LgySfh6achRRMvSiVzqH+SvzWzXwKPDage2DfAOedqlnaimSUDTwMZwAZgoZlNc86tOOC4GsDNwMcHv0olErqs96JFWtZbREQkxNixY7n33nuL9vv27cu4ceMOWTw7B088AcOHe39iwZs99rXXoHv3SGYscvjKvALtnEt2ztUMbDWccykhj0stngPaAqudc9845/YCk4CSxk0/APwd2HNYLYiW2rW9z5XA+21//31/8xEREakkXn75ZW6++eai/YyMDCZOnEjKIS4d79sHf/yjtzR3YfF84onw0UcqnqVyi+T048cB34XsbwjEiphZK+AE59w7EcwjfDSMQ0REpJhp06YxcODAov1zzjmHyZMnk5qaWuZ5P/8M3brBuHHB2LnneuOfW7aMULIiYRLJUUUlfWZTtA62mSUBjwMDD/lCZoOAQQDp6enk5OSQm5tLTk5OeDItp5rHHsuZgcd7pk9nQXa2d4NhBPnRTj8kQjsToY2gdookkuzsbK644goKCgoAOP3005k5cyZpaWllnvf113DJJfDVV8HYNdfA889DtWqRzFgkPCJZQG8ATgjZPx74PmS/BtASyAmMj6oPTDOzXs65RaEv5JwbB4wDaN26tevQoQM5OTkVWskoLM4/H+65B375hWpbttChYUM45ZSIfktf2umDRGhnIrQR1E6RRLFw4UJ69epFXmCVk2bNmvHuu+9Sp06dMs/LyYG+fb0r0IUeeMD78xrha1IiYRPJIRwLgZPNrImZVQV+B0wrfNI59z/n3LHOuROdcycCC4CDiudKJSXFu5mwkIZxiEicMrMJZrbVzL4I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\n",
      "text/plain": [
       "<Figure size 864x432 with 2 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "# Define figure size\n",
    "rcParams['figure.figsize'] = 12, 6\n",
    "\n",
    "# number of cores and runtime\n",
    "cores = np.array([1, 2, 4, 8, 16, 25])\n",
    "t_denise = np.array([0.926, 0.482, 0.234, 0.123, 0.067, 0.055])\n",
    "\n",
    "# speed-up with respect to the runtime of the 1st core\n",
    "# and linear speedup\n",
    "speedup_denise = t_denise[0] / t_denise\n",
    "linear_speedup = cores\n",
    "\n",
    "# plot runtime\n",
    "ax2 = plt.subplot(121)\n",
    "plt.plot(cores, t_denise, 'rs-',lw=3,label=\"Runtime\")\n",
    "plt.title('Runtime DENISE Black-Edition')\n",
    "plt.xlabel('Number of cores')\n",
    "plt.ylabel('Runtime (s)')\n",
    "plt.legend()\n",
    "plt.grid()\n",
    "\n",
    "# plot speedup\n",
    "ax2 = plt.subplot(122)\n",
    "plt.plot(cores, speedup_denise, 'bs-',lw=3,label=\"Speedup DENISE\")\n",
    "plt.plot(cores, linear_speedup, 'k-',lw=3,label=\"Linear speedup\")\n",
    "plt.title('Speedup DENISE Black-Edition')\n",
    "plt.xlabel('Number of cores')\n",
    "plt.ylabel('Speedup')\n",
    "plt.legend()\n",
    "plt.grid()\n",
    "\n",
    "plt.show() "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Using less than 2 cores, the JIT compiled Python code with a runtime of 353 ms is faster than the MPI code. Utilizing more cores, the DENISE code leads to a steady runtime decrease. However, notice that the speedup is not linear anymore when using 16 cores or more. This can be explained by excessive communication time between the MPI processes, when the domain sizes decreases. More details about MPI and Multithreading optimizations are beyond the scope of the TEW2 course, but will be the topic of a future HPC lecture ...\n",
    "\n",
    "To get an idea about the difference between JIT optimized Python codes and manually optimized codes, I recommend a SciPy 2016 talk by Andreas Klöckner:\n",
    "\n",
    "**High Performance with Python: Architectures, Approaches & Applications**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/jpeg": "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\n",
      "text/html": [
       "\n",
       "        <iframe\n",
       "            width=\"400\"\n",
       "            height=\"300\"\n",
       "            src=\"https://www.youtube.com/embed/Zz_6P5qAJck\"\n",
       "            frameborder=\"0\"\n",
       "            allowfullscreen\n",
       "        ></iframe>\n",
       "        "
      ],
      "text/plain": [
       "<IPython.lib.display.YouTubeVideo at 0x7fb8d6a33350>"
      ]
     },
     "execution_count": 24,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from IPython.display import YouTubeVideo\n",
    "YouTubeVideo('Zz_6P5qAJck')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "##### Bonus Exercise (counts as 2 regular exercises)\n",
    "\n",
    "Take the JIT optimized 2D acoustic seismic modelling code and use it as a starting point to write a 3D acoustic modelling code. Compare the numerical solution for a 3D homogeneous medium with the analytical solution. Compare the runtime of the 3D code with the 2D code.\n",
    "\n",
    "##### Bonus-Bonus Exercise (counts as 4.5 regular exercises)\n",
    "\n",
    "Take the JIT optimized 2D acoustic seismic modelling code and use it as a starting point to write a 4D acoustic modelling code. Compare the seismograms of the numerical solution for the 3D and 4D problem. Compare the runtime of the 4D code with the 2D and 3D codes."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## What we learned:\n",
    "\n",
    "* The performance of our 2D acoustic FD modelling code, developed in the previous class, suffered from the nested FOR loops\n",
    "* Using JIT compilation of the Python code using `Numba`, the performance could be significantly improved by a factor 509x\n",
    "* Alternatively, we can replace the nested FOR loops by `NumPy` array operations to improve the runtime performance\n",
    "* The performance of the JIT compiled Python code is comparable with a C++ implementation\n",
    "* Check if the modelling results of your optimized Python codes are still correct"
   ]
  }
 ],
 "metadata": {
  "anaconda-cloud": {},
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.4"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 1
}
